package com.linkgie.galaxyframework.utils.bean;

import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;

import com.linkgie.galaxyframework.utils.CollectionUtils;

public class BeanType {

    private Class<?> beanClass;

    private BeanInfo beanInfo;

    private Set<PropertyDescriptor> properties;

    private List<BeanInfo> additionalBeanInfos;

    /**
     * 创建 BeanType ;
     * 
     * @param beanClass Bean 的类型；可以是类，也可以是接口；
     */
    public BeanType(Class<?> beanClass) {
        this(beanClass, false);
    }

    public BeanType(Class<?> beanClass, boolean allInterfaces) {
        this.beanClass = beanClass;
        this.beanInfo = getBeanInfo(beanClass);
        if (allInterfaces) {
            this.additionalBeanInfos = getAdditionalBeanInfos(beanClass);
        }

        Set<PropertyDescriptor> props = CollectionUtils.merge(beanInfo.getPropertyDescriptors());
        if (this.additionalBeanInfos != null) {
            for (BeanInfo additionalBeanInfo : additionalBeanInfos) {
                CollectionUtils.addAll(props, additionalBeanInfo.getPropertyDescriptors());
            }
        }
        this.properties = Collections.unmodifiableSet(props);
    }

    private static List<BeanInfo> getAdditionalBeanInfos(Class<?> beanInterface) {
        // 只针对接口；
        if (!beanInterface.isInterface()) {
            return CollectionUtils.emptyList();
        }
        ArrayList<BeanInfo> beanInfos = new ArrayList<>();
        getInterfacesBeanInfo(beanInterface, beanInfos);

        beanInfos.trimToSize();
        return beanInfos;
    }

    /**
     * 递归地解析 Bean 信息；
     * 
     * @param beanInterface
     * @param beanInfos
     */
    private static void getInterfacesBeanInfo(Class<?> beanInterface, ArrayList<BeanInfo> beanInfos) {
        Class<?>[] superIntfs = beanInterface.getInterfaces();
        for (Class<?> superIntf : superIntfs) {
            beanInfos.add(getBeanInfo(superIntf));
            // 递归解析上一级接口；
            getInterfacesBeanInfo(superIntf, beanInfos);
        }
    }

    private static BeanInfo getBeanInfo(Class<?> beanClass) {
        try {
            return Introspector.getBeanInfo(beanClass);
        } catch (IntrospectionException e) {
            throw new IllegalStateException(e.getMessage(), e);
        }
    }

    public Set<PropertyDescriptor> getPropertyDescriptors() {
        return this.properties;
    }

}
